﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using AZROLESLib;
using AzManContrib.MVC.Html.Behaviors;
using System.Web.Mvc.Html;

namespace AzManContrib.MVC.Html
{
    public static class ValidationExtensions
    {
        /* 
         * Non generic with operation by name
         */
        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string operation)
        {
            return ValidationMessageFor(htmlHelper, expression, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, string operation)
        {
            return ValidationMessageFor(htmlHelper, expression, validationMessage, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, object htmlAttributes, string operation)
        {
            return ValidationMessageFor(htmlHelper, expression, validationMessage, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, IDictionary<string, object> htmlAttributes, string operation)
        {
            return ValidationMessageFor(htmlHelper, expression, validationMessage, htmlAttributes, AzMan.Application.Operations.FindByName(operation));
        }

        /* 
         * Non generic method, thus using AzMan.Defaults.UI.DenyiedBehavior 
         */
        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, IAzOperation, MvcHtmlString> genMethod = ValidationMessageFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, string, IAzOperation, MvcHtmlString> genMethod = ValidationMessageFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, validationMessage, operation }) as MvcHtmlString;
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, object htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, string, object, IAzOperation, MvcHtmlString> genMethod = ValidationMessageFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new [] { htmlHelper, expression, validationMessage, htmlAttributes, operation }) as MvcHtmlString;
        }


        public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, IDictionary<string, object> htmlAttributes, IAzOperation operation)
        {
            Func<HtmlHelper<TModel>, Expression<Func<TModel, TProperty>>, string, IDictionary<string, object>, IAzOperation, MvcHtmlString> genMethod = ValidationMessageFor<TModel, TProperty, HiddenUIBehavior>;
            MethodInfo method = genMethod.Method.GetGenericMethodDefinition();
            MethodInfo generic = method.MakeGenericMethod(new[] { typeof(TModel), typeof(TProperty), AzMan.Defaults.UI.DenyiedBehavior });
            return generic.Invoke(htmlHelper, new object[] { htmlHelper, expression, validationMessage, htmlAttributes, operation }) as MvcHtmlString;
        }

        /* 
         * Generic methods, thus you can provide an inhibition behavior.
         */
        public static MvcHtmlString ValidationMessageFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ValidationMessageFor<TModel, TProperty, TBehavior>(htmlHelper, expression, null /* validationMessage */, new RouteValueDictionary(), operation);
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ValidationMessageFor<TModel, TProperty, TBehavior>(htmlHelper, expression, validationMessage, new RouteValueDictionary(), operation);
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, object htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            return ValidationMessageFor<TModel, TProperty, TBehavior>(htmlHelper, expression, validationMessage, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), operation);
        }

        public static MvcHtmlString ValidationMessageFor<TModel, TProperty, TBehavior>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, IDictionary<string, object> htmlAttributes, IAzOperation operation)
            where TBehavior : IUIBehavior, new()
        {
            TBehavior behavior = new TBehavior();

            if (!HttpContext.Current.User.Can(operation))
            {
                if (!behavior.ShouldRender)
                    return MvcHtmlString.Empty;
                return htmlHelper.ValidationMessageFor(expression, validationMessage, behavior.GetHtmlAttributes(htmlAttributes));
            }
            return htmlHelper.ValidationMessageFor(expression, validationMessage, htmlAttributes);
        }
    }
}